/**
 * @file lv_ime_pinyin.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_ime_pinyin.h"
#if LV_USE_IME_PINYIN != 0

#include <stdio.h>

/*********************
 *      DEFINES
 *********************/
#define MY_CLASS    &lv_ime_pinyin_class

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_ime_pinyin_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_ime_pinyin_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_ime_pinyin_style_change_event(lv_event_t * e);
static void lv_ime_pinyin_kb_event(lv_event_t * e);
static void lv_ime_pinyin_cand_panel_event(lv_event_t * e);

static void init_pinyin_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict);
static void pinyin_input_proc(lv_obj_t * obj);
static void pinyin_page_proc(lv_obj_t * obj, uint16_t btn);
static char * pinyin_search_matching(lv_obj_t * obj, char * py_str, uint16_t * cand_num);
static void pinyin_ime_clear_data(lv_obj_t * obj);

#if LV_IME_PINYIN_USE_K9_MODE
    static void pinyin_k9_init_data(lv_obj_t * obj);
    static void pinyin_k9_get_legal_py(lv_obj_t * obj, char * k9_input, const char * py9_map[]);
    static bool pinyin_k9_is_valid_py(lv_obj_t * obj, char * py_str);
    static void pinyin_k9_fill_cand(lv_obj_t * obj);
    static void pinyin_k9_cand_page_proc(lv_obj_t * obj, uint16_t dir);
#endif

/**********************
 *  STATIC VARIABLES
 **********************/
const lv_obj_class_t lv_ime_pinyin_class = {
    .constructor_cb = lv_ime_pinyin_constructor,
    .destructor_cb  = lv_ime_pinyin_destructor,
    .width_def      = LV_SIZE_CONTENT,
    .height_def     = LV_SIZE_CONTENT,
    .group_def      = LV_OBJ_CLASS_GROUP_DEF_TRUE,
    .instance_size  = sizeof(lv_ime_pinyin_t),
    .base_class     = &lv_obj_class
};

#if LV_IME_PINYIN_USE_K9_MODE
static char * lv_btnm_def_pinyin_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 21] = {\
                                                                                ",\0", "123\0",  "abc \0", "def\0",  LV_SYMBOL_BACKSPACE"\0", "\n\0",
                                                                                ".\0", "ghi\0", "jkl\0", "mno\0",  LV_SYMBOL_KEYBOARD"\0", "\n\0",
                                                                                "?\0", "pqrs\0", "tuv\0", "wxyz\0",  LV_SYMBOL_NEW_LINE"\0", "\n\0",
                                                                                LV_SYMBOL_LEFT"\0", "\0"
                                                                               };

static lv_btnmatrix_ctrl_t default_kb_ctrl_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 17] = { 1 };
static char   lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 2][LV_IME_PINYIN_K9_MAX_INPUT] = {0};
#endif

static char   lv_pinyin_cand_str[LV_IME_PINYIN_CAND_TEXT_NUM][4];
static char * lv_btnm_def_pinyin_sel_map[LV_IME_PINYIN_CAND_TEXT_NUM + 3];

#if LV_IME_PINYIN_USE_DEFAULT_DICT
lv_pinyin_dict_t lv_ime_pinyin_def_dict[] = {
    { "a", "啊呵阿" },
    { "ai", "唉碍隘癌爱蔼哀埃哎艾矮挨" },
    { "an", "厂安鞍暗氨黯按庵案岸俺广" },
    { "ang", "昂仰肮" },
    { "ao", "袄熬澳傲懊拗奥凹" },
    { "b", "弊宝渤被般簸必瓣蔽惫彪叭痹频脖崩暴拌拜饱颁膀憋怖辟缤芭伴便壁捌柏扒卜瀑禀梆悖北堡伯冰拂柄绊八杯豹板褒谤辩逼病罢布标搏别笨补簿臂背屏卑蝙邦滨爆鳖傍帮抱舶霸玻雹饼百薄备辈倍丙磅榜疤辨掰悲扁泊遍棒 菠巴庇斑鞭班旁秉半毕博保边表蹦绷鄙包蚌匕扮波泵濒捕拔坝镑步碧彭币鼻笔驳报本摆跋跛曝彬部份彼把不耙炮比秘胞剥白毙败编璧刨搬爸匾勃版鬓碑靶闭贝吧宾狈泌拨扳兵避瘪鲍辫播贬膊绑奔并斌办夯变佛苞埠哺" },       
    { "ba", "把耙疤吧伯爸跋捌扒拔霸芭坝罢八叭巴靶" },
    { "bai", "败伯掰摆柏拜白百" },
    { "ban", "颁般斑办搬伴版半拌绊瓣班扮扳板" },
    { "bang", "膀梆傍蚌榜邦帮旁磅镑绑棒谤彭" },
    { "bao", "包薄爆鲍瀑褒宝堡抱报刨炮雹暴曝苞豹保胞剥饱" },
    { "bei", "贝备碑辈倍勃北悖被悲臂狈背卑惫杯" },
    { "ben", "夯笨本奔" },
    { "beng", "蚌崩蹦泵绷" },
    { "bi", "弊庇璧逼必毕毙鼻闭痹匕鄙蔽臂泌碧避笔辟壁彼币拂比秘佛" },
    { "bian", "鞭蝙编辩辫贬便匾扁遍边变辨" },
    { "biao", "标彪表" },
    { "bie", "鳖别瘪憋" },
    { "bin", "斌鬓缤宾濒频滨彬份" },
    { "bing", "禀冰丙病兵柄秉屏饼并" },
    { "bo", "脖渤簸勃博膊搏簿拨播舶玻柏跛卜薄驳伯泊佛菠波剥" },
    { "bu", "布不怖堡部簿捕补卜埠步哺" },
    { "c", "脆伺祠词凑卒搓错窜参差醋餐蚕猜趣粹磁苍糙撮才菜匆仓策篡槽次衰催彩残崔促采藏惭曹册挫舱辞拆从曾厕蔡措掺雌财惨兹侧刺慈此睬测擦蹭葱踩粗沧趋瓷簇丛悴草村摧灿层操材存聪囱裁栅寸翠赐" },
    { "ca", "擦拆" },
    { "cai", "猜财采裁才踩菜材彩蔡睬" },
    { "can", "残餐蚕掺参惨惭灿" },
    { "cang", "沧舱苍藏仓" },
    { "cao", "草操糙曹槽" },
    { "ce", "栅册厕侧测策" },
    { "cen", "参" },
    { "ceng", "层蹭曾" },
    { "ch", "瞅翅窗尘纯场础呈敞除愁吃厂沈醇肠长蝉耻插差沉茬喳抽迟淳澄床喘初钞倡抢春吹净橙雏称柴超成猖稠斥茶常陈种乘晨臭衬潮持程岔创撤冲畅缠城重锄蠢锤澈尺酬闯侈炒触宠吵拆齿痴趁搀昌椎倘疮产畜查仇豺铛赤池裳垂抄朝储唱掺单扯穿剿撑诚唇嘲察臣幢惩盛承禅绸阐馋叉船楚川车畴匙忱颤驰崭戳逞充捶巢虫绰筹出偿处传助串秤揣崇炊涌丑弛尝橱厨辰刹椿淌铲彻" },
    { "cha", "茶岔茬喳刹叉插察查差" },
    { "chai", "拆差柴豺" },
    { "chan", "搀禅阐产颤崭掺蝉单馋缠铲" },
    { "chang", "厂昌猖倘尝倡肠唱常场畅淌敞裳长偿" },
    { "chao", "抄炒超朝钞嘲吵巢潮绰剿" },
    { "che", "澈撤尺车扯彻" },
    { "chen", "趁沉沈尘衬辰臣陈晨忱称" },
    { "cheng", "成铛呈乘盛程逞城诚撑惩澄抢净橙秤称承" },
    { "chi", "斥翅池驰持吃匙耻尺迟赤侈弛齿痴" },
    { "chong", "崇宠虫冲充重种涌" },
    { "chou", "愁瞅丑稠抽仇酬臭畴筹绸" },
    { "chu", "锄础楚除储出处助畜触初雏橱厨" },
    { "chua", "" },
    { "chuai", "揣" },
    { "chuan", "喘传串船川穿" },
    { "chuang", "床窗创疮幢闯" },
    { "chui", "垂炊椎锤吹捶" },
    { "chun", "唇蠢春醇纯椿淳" },
    { "chuo", "戳绰" },
    { "ci", "磁辞次词刺雌慈祠伺此赐差瓷兹" },
    { "cong", "匆聪丛葱从囱" },
    { "cou", "凑" },
    { "cu", "簇趋趣醋促卒粗" },
    { "cuan", "窜篡" },
    { "cui", "脆衰催悴粹翠摧崔" },
    { "cun", "村寸存" },
    { "cuo", "搓错挫措撮" },
    { "d", "待袋怠吨递电稻盯调掂的栋订瞪洞兑毒董囤迪独惰滴堆底第玷甸冻戴奠顶澄弟胆痘惦导刀蚪盗到躲巅蹈低代咄短蹬妒端逗挡弹悼达懂邓荡追睹跺赌吊倒兜盹读都刁豆抖笛涤大瘩丹耽佃颠提当叠督叼店鼎岛东段朵滇铛缎淡敦碘定石碟道单档旦迭丢墩逮抵德点殿镀担呆谍答杜凳典帝舵锻淀哆嘀掉隋冬多踱堤断钉夺但蛋党蝶对得动蹲等打诞缔灯叮歹登顿斗垛氮钝带垫地敌队钓丁蒂堕肚渡度搭堵贷爹祷跌陡捣叨雕盾" },
    { "da", "大瘩搭达打答" },
    { "dai", "待袋逮怠大带戴贷呆毒代歹" },
    { "dan", "但蛋淡弹单诞旦氮担石丹耽胆" },
    { "dang", "挡荡档当铛党" },
    { "dao", "刀倒岛到稻悼蹈道盗捣叨祷导" },
    { "de", "得地底德的" },
    { "dei", "得" },
    { "den", "" },
    { "deng", "邓澄瞪凳等蹬灯登" },
    { "di", "嘀迪堤递低的滴蒂底缔第地抵敌笛帝弟提涤" },
    { "dia", "" },
    { "dian", "掂店碘颠滇垫电玷点殿淀佃巅甸奠惦典" },
    { "diao", "刁调吊掉雕钓叼" },
    { "die", "谍碟跌爹叠迭蝶" },
    { "ding", "丁钉鼎定订顶盯叮" },
    { "diu", "丢" },
    { "dong", "栋冬东动洞懂冻董" },
    { "dou", "蚪斗抖逗豆痘兜陡读都" },
    { "du", "妒肚渡度堵镀赌毒读杜督独睹都" },
    { "duan", "缎断段锻短端" },
    { "dui", "堆队兑敦追对" },
    { "dun", "钝墩吨囤敦蹲盹顿盾" },
    { "duo", "咄垛舵堕多度躲踱朵夺哆隋惰跺" },
    { "e", "鄂讹阿扼愕鳄遏峨额恶娥鹅俄哦噩饿蛾" },
    { "ei", "欸诶" },
    { "en", "恩嗯唔摁蒽" },
    { "er", "二尔贰耳饵儿而" },
    { "f", "辅缚废方讽放附坊反罚凡浮诽仿覆贩芬费沸乏菲粉腐伏肥俯忿吩夫纺拂幅奋富坟烦妨符发非番复芙付愤饭矾妇分逢疯父法赴扶负俘蜂吠匪犯纷泛返服咐氛缝府房奉啡副峰孵腹妃否访份封锋不弗抚甫赋筏风飞阀粪焚丰芳肺繁傅帆福伐袱斧枫冯防蝠翻范辐肪脯佛肤凤敷" },
    { "fa", "阀伐乏发法筏罚" },
    { "fan", "犯反泛凡番贩饭帆翻范繁返烦矾" },
    { "fang", "肪坊妨芳防方纺房放访仿" },
    { "fei", "妃废吠肥匪沸肺飞非啡费菲诽" },
    { "fen", "粪分氛焚愤吩芬粉纷奋坟份忿" },
    { "feng", "封蜂疯缝枫冯锋丰讽逢奉风凤峰" },
    { "fiao", "覅" },
    { "fo", "佛" },
    { "fou", "否不" },
    { "fu", "辅缚符附浮覆复咐府肤富赴付副孵腹傅妇福斧袱父服蝠芙俯扶伏辐弗抚负夫脯拂幅赋俘佛腐敷甫" },
    { "g", "挂合鼓疙贾谷姑狗巩馆隔逛港改秆蛤括共更广高钙甘扛龟搞钩个鬼菇歌肛感汞割跪构羔庚冠辜滚赣固褂各梗沟管蚣尴羹格灌该钢寡工卦癸概贵观故拐涡溉咕诡肝宫缸桂告棍糕给跟哥轨郭公拱乾弓贯恭躬功橄雇归苟句瑰 胳稿赶竿颈革贡垢纲夹埂光葛刚芥股镐孤干裹国顾搁冈咖果红根攻鸽柜古关戈丐岗尬杆柑敢惯骨购耿拘瓜膏锅供怪刮估沽闺罐乖杠阁耕官够过硅规盖棺勾" },
    { "ga", "咖尬夹" },
    { "gai", "概溉丐钙芥改盖该" },
    { "gan", "甘感橄肝秆尴杆柑赣敢干竿赶乾" },
    { "gang", "岗冈肛刚扛钢港纲缸杠" },
    { "gao", "膏羔告镐糕高搞稿" },
    { "ge", "各合疙戈格胳隔葛蛤革阁个歌哥割搁鸽盖" },
    { "gei", "给" },
    { "gen", "根跟艮亘茛" },
    { "geng", "颈耕梗庚羹耿埂更" },
    { "gong", "弓供功贡共蚣红宫躬攻汞工巩恭公拱" },
    { "gou", "构沟垢钩购够狗拘苟句勾" },
    { "gu", "贾姑骨谷故咕股估沽菇孤鼓顾辜雇古固" },
    { "gua", "挂褂刮括瓜寡卦" },
    { "guai", "怪拐乖" },
    { "guan", "官冠馆管观灌罐惯关贯棺" },
    { "guang", "逛光广" },
    { "gui", "归瑰癸贵闺诡龟桂轨鬼跪硅规柜" },
    { "gun", "棍滚" },
    { "guo", "锅果涡过郭裹国" },
    { "h", "怀喉合会皇咳胡诲荒话换鹤撼厂徊褐昏吓卉户嘿蝴黄哈捍寒何惠虎浩火淮后划涣亥河侯桦号候魂秽汉坏赫贿凰荷惶溃辉皓化洪涵骇贺毁蝗行痕苛画函喊耗伙宦晃哄狐狠槐痪好悍或弘唤讳花衡棍慌乎恒恢毫豪虾很嚎沪壶 恍煌回黑慧呵虹灰韩湖患核徽幌恨晦旱禾忽霍戏厚挥护轰含憾混浑烘葫杭镐宏横环猴婚蛤荤缓祸互红弧憨鸿活豁盒酣货焊欢喝吼猾华哗许谎呼和焕悔簧糊汇汗孩幻哼航还唬害获绘滑巷堕翰吭夯盖惑罕海" },
    { "ha", "蛤哈虾" },
    { "hai", "骇亥咳害还孩海" },
    { "han", "涵焊韩撼旱憾函厂喊含捍寒罕汗悍憨汉酣翰" },
    { "hang", "航吭夯行杭巷" },
    { "hao", "皓耗镐嚎浩毫豪号好" },
    { "he", "合喝河核贺苛鹤和吓禾何盒褐盖赫呵荷" },
    { "hei", "黑嘿" },
    { "hen", "狠恨痕很" },
    { "heng", "横恒衡哼" },
    { "hong", "洪鸿哄烘宏弘轰红虹" },
    { "hou", "喉后候厚侯猴吼" },
    { "hu", "胡忽呼和戏核护户糊狐虎葫唬乎湖蝴互弧沪许壶" },
    { "hua", "豁划化花猾华滑哗话画桦" },
    { "huai", "怀槐徊淮坏" },
    { "huan", "患欢换焕痪幻涣唤环缓还宦" },
    { "huang", "皇晃谎黄煌簧恍慌幌荒蝗凰惶" },
    { "hui", "溃辉徽毁诲灰秽悔会挥汇卉讳惠绘恢晦堕贿回慧" },
    { "hun", "昏魂混棍浑婚荤" },
    { "huo", "和或货伙活豁获霍惑祸火" },
    { "i", "" },
    { "j", "稼揭其俊教景基巾槛畸节纪稽精今姐几巨卷较结兢践技加降江匠九狡绩搅记捐佳具箕级讲浆煎句继灸系贱妓舅眷柬极靖脚距据俱拘阶界减进聚敬驾掘鞠紧尽浇襟健臼焦强见藉经金叽鲸疾检蕉剧倦仅击期沮久建舰圾荆酒矩艰家楷浅街诫究兼诀筋剑骏锦俭洁京夹嚼菊棘救她剿颊剪奸挟忌柜绢秸脊倔钧橘竣纠饥监杰鸡唧激惊籍季驹且谨键机贾坚娇井龟碱缴剂歼冀净际菌饺捷胶轿椒劫警缉肌玖疚炬角捡静举届叫斤锯奇姜绞蒋接竟桨韭己颈娟将芥挤 绝崛就茎辑渐溅近桔拣车港架晋既涧缰嫉矫晶窘急竞睫禁侥箭济奖礁交寂酱戒军竭浸径吉校茧觉劲拒计惧迹钾津鹃假峻祭圈嫁荐给简嘉窖居跤间境讥鲫局鉴价骄疆君及揪尖肩截决解爵寄均渠甲介借酵镜旧积僵皆集郊睛即件" }, 
    { "ji", "极箕计讥级记机圾脊济继己迹系叽技缉绩击奇集疾寂籍及鲫棘既祭其妓肌挤吉剂嫉给积畸冀辑期鸡急唧纪藉饥稽激际寄忌几季基即" },
    { "jia", "甲稼架价加家夹假贾驾嫁嘉颊挟钾佳" },
    { "jian", "渐箭键舰见拣煎浅坚俭艰鉴贱检捡兼溅尖涧肩碱减监荐槛剪奸歼简茧践间件剑健柬建" },
    { "jiang", "将匠疆港缰讲强蒋浆降奖姜江酱僵桨" },
    { "jiao", "椒脚侥焦觉饺叫礁骄娇交嚼蕉教角酵剿较缴狡矫搅窖校浇郊绞跤轿胶" },
    { "jie", "接劫藉介结桔揭价洁借家街她戒芥截阶届界解诫竭杰节皆捷姐睫楷秸" },
    { "jin", "禁谨近津晋锦巾进浸仅斤劲尽筋今襟金紧" },
    { "jing", "境茎荆靖竟兢警经颈京鲸静景井镜敬晶径劲精净惊睛竞" },
    { "jiong", "窘" },
    { "jiu", "揪舅玖疚纠就久救酒九旧韭臼究灸" },
    { "ju", "且沮渠句局桔橘距惧车据矩炬菊拘剧举俱聚鞠锯居拒柜巨具驹" },
    { "juan", "圈娟倦眷捐绢卷鹃" },
    { "jun", "骏龟军君均钧俊菌竣峻" },
    { "jue", "倔觉嚼角决绝掘崛爵诀" },
    { "k", "亏抗会咳渴宽科恐拷阔客盔括垮控枯寇框槛裤坤矿啃狂克跨筷溃库颗捆坎廓苛刻扛卡酷筐砍愧苦呵楷窟康壳窥糠恳葵刊夸孔慨可空馈咖亢块铐坷挎肯况眶款考叩揩垦坑勘扣烤困课开昆炕堪嵌磕魁靠口快哭凯棵旷岂看吭 慷抠蝌扩" },
    { "ka", "卡咖" },
    { "kai", "开岂揩慨凯楷" },
    { "kan", "看刊砍堪嵌坎勘槛" },
    { "kang", "炕抗亢康扛糠慷" },
    { "kao", "靠考拷铐烤" },
    { "ke", "颗咳渴苛壳客刻课蝌磕可棵克科呵坷" },
    { "kei", "" },
    { "ken", "啃垦恳肯" },
    { "keng", "吭坑" },
    { "kong", "控恐孔空" },
    { "kou", "抠寇扣口叩" },
    { "ku", "挎库窟枯裤苦哭酷" },
    { "kua", "跨垮夸挎" },
    { "kuai", "会筷块快" },
    { "kuan", "宽款" },
    { "kuang", "况眶狂框筐旷矿" },
    { "kui", "溃亏窥愧葵盔馈魁" },
    { "kun", "昆捆坤困" },
    { "kuo", "阔廓扩括" },
    { "l", "料瘤临肋卢绿缕录离牢棱老锣旅骡侣连略冷礼嘹凌窿螺雷溜聋劣良类林唠砾卤婪朗洛澜览郎峦鹿猎涝箩辆陋痢狸搂量篓庐笼了粒榴隶擂乱零邻莲逻狼梁聆哩勒链怜莱立寥轮菱磷碌栗鲤氯炼另路柳谅吕亮裂黎履啦流垒赁 厘敛屡莉咧赂腊捞姥酪律馏拉聊睐吏蓝榄萝璃列镰恋虏留来咙垄领六廊鳞拢李俩浪篱犁垃抡廉楼琅骆漓掠烂泪瞭玲辽驴赖梨络粱脸烙滤愣沦丽联缆刘伦乐蜡里疗仑榔磊拎俐僚躏两铃揽蕾羚琳令硫弄率撩凛滥兰龄琉漏粮龙帘练胧 雳历懒辣沥励晾芦陆累陵浏拦娄露凉力缭论烈卵裸鲁理炉淋荔啰罗利厉劳伶栏篮颅喇例岭铝禄隆吝落虑灵" },
    { "la", "垃喇蜡辣落拉腊啦" },
    { "lai", "莱睐赖来" },
    { "lan", "榄缆栏澜蓝览烂滥拦婪篮兰懒揽" },
    { "lang", "琅榔朗廊郎浪狼" },
    { "lao", "老涝唠劳落乐烙络捞牢姥酪" },
    { "le", "了肋勒乐" },
    { "lei", "肋垒累擂雷磊勒泪类蕾" },
    { "leng", "愣棱冷" },
    { "li", "璃厉力理莉立李篱雳历吏砾栗鲤黎梨痢狸犁例沥励离礼哩漓粒厘利隶丽里俐荔" },
    { "lia", "俩" },
    { "lian", "帘怜练联镰莲炼恋连敛脸廉链" },
    { "liang", "梁谅两辆亮粱凉量粮俩良晾" },
    { "liao", "了瞭疗料缭撩嘹辽聊僚寥" },
    { "lie", "猎列劣咧裂烈" },
    { "lin", "赁躏林吝琳邻临淋拎凛鳞磷" },
    { "ling", "伶铃菱羚玲令另岭聆棱龄领灵凌陵零" },
    { "liu", "碌刘溜馏瘤琉榴流浏留硫六柳" },
    { "lo", "" },
    { "long", "垄隆咙龙弄笼聋拢胧窿" },
    { "lou", "搂娄漏露陋篓楼" },
    { "lu", "赂卢绿碌庐虏录六鹿鲁颅炉露卤路禄芦陆" },
    { "luan", "乱峦卵" },
    { "lue", "掠略" },
    { "lun", "抡伦论沦仑轮" },
    { "luo", "骆洛萝锣箩逻落罗烙络螺啰裸骡" },
    { "lv", "率律吕侣氯驴旅绿铝屡虑履滤缕" },
    { "m", "霉茂莽母摸缅氓枚弥檬绵嘿姆牧米默蒙贸渺芒皿码骂瞄蔓媒拇梦眯幕摩门摹馍锚盟眠忙慢眉冒鸣密免秒莫明秘庙玛亩木玫谋穆毛猛膜模猫咪暮敏牡昧目墓妙沫妹陌募面矛茅万脉蔑沐瞒墨魅磨们曼没锰马棉每魔蘑迷蚂妈民媚么帽藐孟卯盲漫卖萌谜冥朦谬悯麻觅姥睦买闽茉貌吗嘛蜜迈蟆泌慕寞靡梅苗漠抹勉埋美满煤铭闷灭名馒蛮麦末某描茫命" },
    { "ma", "码蚂妈骂吗玛嘛抹麻蟆么摩马" },
    { "mai", "脉麦迈埋卖买" },
    { "man", "馒蔓瞒蛮埋满慢曼漫" },
    { "mang", "氓芒茫莽忙盲" },
    { "mao", "茅冒矛猫贸帽茂貌毛锚卯" },
    { "me", "么" },
    { "mei", "梅眉美媒魅枚没媚昧玫霉妹每煤" },
    { "men", "瞒门们闷" },
    { "meng", "萌檬氓蒙猛梦锰盟孟朦" },
    { "mi", "谜觅弥密泌靡米蜜迷咪眯秘" },
    { "mian", "缅勉眠棉免面绵" },
    { "miao", "瞄庙妙苗渺描藐秒" },
    { "mie", "蔑灭" },
    { "min", "民悯敏闽皿" },
    { "ming", "名明鸣冥铭命" },
    { "miu", "谬" },
    { "mo", "馍沫么陌摸万茉冒墨嘿蟆默漠寞没莫脉抹磨蘑膜模末摩摹魔" },
    { "mou", "谋某" },
    { "mu", "沐墓目模亩木暮拇姆母穆幕募牡姥牧睦慕莫" },
    { "n", "馁耐娜拗拧念年奶闹脑粘鸟懦孽弄逆钮溺囊浓南瑙泞扭宁纳摄凝糯恼尿乃挠牛怒疟撵聂泥能农难哪捻疑腻那挪呐拟捺拿钠您妮诺辗纽奈脓努匿碾捏女内娘尼虐你呢嫩奴暖男狞柠酿" },
    { "na", "内娜那纳钠呐南哪捺拿" },
    { "nai", "耐乃奈奶能" },
    { "nan", "男难南" },
    { "nang", "囊" },
    { "nao", "脑挠瑙闹恼" },
    { "ne", "呢呐哪" },
    { "nei", "馁那内哪" },
    { "nen", "嫩" },
    { "neng", "能" },
    { "ni", "溺逆疑腻妮拟尼匿你呢泥" },
    { "nian", "辗粘撵碾念年捻" },
    { "niang", "娘酿" },
    { "niao", "鸟溺尿" },
    { "nie", "聂摄捏捻孽" },
    { "nin", "您" },
    { "ning", "宁狞凝泞柠拧" },
    { "niu", "牛纽扭拗钮" },
    { "nong", "弄脓农浓" },
    { "nou", "" },
    { "nu", "努怒奴" },
    { "nuan", "暖" },
    { "nue", "疟虐" },
    { "nuo", "娜挪难懦糯诺" },
    { "nv", "女" },
    { "o", "哦" },
    { "ou", "鸥欧藕殴呕区偶" },
    { "p", "漂骗被爬砰派碰牌坪僻铺排暴片拌鹏乓拼频朴便篇拍扒陪譬篷瀑帕堡胖捧抛披罢翩啪凭培澎霹湃配屏盘佩平螃袍婆畔剖潘叛啤普圃坯徘庞皮趴扁泊扑赔沛判脾旁跑聘浦飘彭副盼攀妃否品魄乒曝泡票烹耙膨贫炮谱屁评葡 瓶撇刨蒲破颇菩番劈盆疲辟匹偏坡蓬泼胚冯喷磅迫苹朋萍怕脯繁仆棚瓢批" },
    { "pa", "啪爬扒怕趴耙帕" },
    { "pai", "湃拍牌排徘迫派" },
    { "pan", "攀盘判拌畔胖潘叛番盼" },
    { "pang", "螃庞旁磅乓胖" },
    { "pao", "袍抛炮刨跑泡" },
    { "pei", "妃沛配赔胚佩陪培" },
    { "pen", "盆喷" },
    { "peng", "蓬朋澎膨砰碰苹鹏棚捧彭篷烹" },
    { "pi", "披霹罢僻劈譬疲匹副被辟否啤脾皮屁坯批" },
    { "pian", "骗篇便扁片偏翩" },
    { "piao", "漂飘朴瓢票" },
    { "pie", "撇" },
    { "pin", "频贫品聘拼" },
    { "ping", "萍冯评屏乒坪凭平瓶苹" },
    { "po", "颇朴破繁魄婆泊坡迫泼" },
    { "pou", "剖" },
    { "pu", "圃堡谱脯朴暴葡仆扑曝瀑铺浦菩普蒲" },
    { "q", "琴崎且蚯侵强屈棋乔寝泣揭雀恰晴顷球切琼纤枪歉锹痊契秦躯栖劝钳妻泉俏欺请清期抢群稽擎囚歧青黔砌气丘卿禽器七缉迄启浅前其氢渠取卡圈缺欠娶去乞乾弃掐铅侨权瘸奇翘腔犬枝区仇谴壳嵌疆悄柒呛遣勤茄趋墙戚 瞧钱倾祈裙潜全却岖钦亲穷蜻曲牵沁窃漆券迁窍脐拳敲签企凄撬怯龟洽齐趣谦骑芹求情鳍旗巧峭跷岂庆憔驱秋千鹊确擒桥起轻汽" },
    { "qi", "漆崎枝欺棋砌泣器迄揭其气企七启契柒骑脐栖戚缉妻祈鳍旗乞歧弃岂期稽凄奇齐起汽" },
    { "qia", "掐洽卡恰" },
    { "qian", "钳迁谴浅签纤歉黔遣欠谦钱铅嵌潜乾千前牵" },
    { "qiang", "疆墙抢枪强腔呛" },
    { "qiao", "乔壳敲悄撬锹雀窍瞧俏巧峭跷憔侨翘桥" },
    { "qie", "窃切怯茄砌契且" },
    { "qin", "沁秦禽钦亲侵琴芹擒寝勤" },
    { "qing", "庆清氢亲蜻倾情青擎晴请顷轻卿" },
    { "qiong", "琼穷" },
    { "qiu", "丘蚯仇球龟求秋囚" },
    { "qu", "渠躯区屈取趋趣娶去岖曲驱" },
    { "quan", "圈犬劝痊泉券权全拳" },
    { "que", "瘸雀鹊缺确却" },
    { "qun", "群裙" },
    { "r", "然若饶兑蓉绕瑞柔软儒蕊人日扰如瓤壬乳冗染热冉融嚷忍扔润肉锐燃蹂仍容韧惹认绒闰女榕让纫辱揉任刃褥弱入壤戎茸仁蠕熔溶汝荣" },
    { "ran", "冉然燃染" },
    { "rang", "壤让嚷瓤" },
    { "rao", "饶扰绕" },
    { "re", "若热惹" },
    { "ren", "刃认纫人仁忍任韧壬" },
    { "reng", "仍扔" },
    { "ri", "日" },
    { "rong", "融戎榕熔冗容蓉溶绒茸荣" },
    { "rou", "肉蹂揉柔" },
    { "ru", "如儒蠕褥辱汝入女乳" },
    { "ruan", "软" },
    { "rui", "瑞蕊兑锐" },
    { "run", "润闰" },
    { "ruo", "若弱" },
    { "s", "俗肃随涩溯伺参穗萨算祀嗓巳色送私肆讼嫂桑散搔粟伞叁所僧松缩尿瑟扫宋撕梭斯遂三笋思梢死唆琐隧耸苏腮司锁丧索嗦寺岁似宿塞酸碎骚丝诵赛损森虽隋洒些搜塑颂诉髓艘四食嗽蒜速饲素臊孙酥嘶撒祟" },
    { "sa", "洒萨撒" },
    { "sai", "腮思赛塞" },
    { "san", "三伞叁参散" },
    { "sang", "丧桑嗓" },
    { "sao", "搔骚梢嫂臊扫" },
    { "se", "涩瑟塞色" },
    { "sen", "森" },
    { "seng", "僧" },
    { "sh", "涉漱售尸傻舌士设沈甩鲨是失参扇哨衫声史适湿上舒沙伤谁吮甸烁睡绅始屎受属拭饰牲柿帅式树抒术申爽双束煽召使射师甚审删水神摄摔乘奢汤烧氏殖陕甥升厦熟十识杉手胜啥闪兽叔砂赎疏蔬输尚薯伸擅曙石婶善首耍逝生圣梢赏竖侍涮舍梳收势社刷蛇商晌慎淑试煞赦深裳殊栓枢视稍掺恃珊单霎赡矢拴时呻渗市霜守似绍晒示数寿少室瞬肾山说勺禅事誓署率身施衰捎刹盛信省蚀蟀匙折绳朱什硕蜀墅税暑世筛鼠瘦纱杀驶书顺泽栅授笙庶实诗释恕 食嗜剩狮述拾" },
    { "sha", "砂沙纱厦鲨傻杀杉刹霎煞啥" },
    { "shai", "晒筛" },
    { "shan", "禅删扇掺杉珊单赡衫闪煽陕擅栅善山" },
    { "shang", "上尚裳商晌赏伤汤" },
    { "shao", "稍少梢绍捎烧哨召勺" },
    { "she", "射涉舌折设社摄蛇舍奢赦拾" },
    { "shei", "" },
    { "shen", "甚审身申慎神信深什沈渗参呻绅婶伸肾" },
    { "sheng", "省笙生圣甥绳升甸乘盛胜剩声牲" },
    { "shi", "师事侍誓食尸示施势士试氏殖匙实饰识是失十什恃视释矢史时湿市蚀世似始屎诗拭石泽柿栅适式逝室硕驶嗜狮使拾" },
    { "shou", "授首瘦售收手守受兽寿" },
    { "shu", "朱梳淑署殊枢漱蜀墅疏暑舒熟鼠蔬薯曙属书数树抒述术庶输恕叔竖赎束" },
    { "shua", "耍刷" },
    { "shuai", "蟀率甩衰摔帅" },
    { "shuan", "涮栓拴" },
    { "shuang", "霜爽双" },
    { "shui", "睡谁说税水" },
    { "shun", "顺瞬吮" },
    { "shuo", "烁硕数说" },
    { "si", "伺私四食祀饲寺撕斯似嘶巳肆丝思司死" },
    { "song", "送宋颂耸讼诵松" },
    { "sou", "搜艘嗽" },
    { "su", "素缩溯诉粟宿肃塑苏俗酥速" },
    { "suan", "算酸蒜" },
    { "sui", "岁穗隋碎遂祟尿髓随隧虽" },
    { "sun", "笋孙损" },
    { "suo", "锁唆琐些缩梭所索嗦" },
    { "t", "退谈唾蹄桐统烫替探抬脱蹋艇滔棠囤填吞踢甸彤跳桶态土鸵弟臀屉淘筒萄涕贪停汤恬檀挑椭弹胎屯偷突堂调趟炭瞳贴摊踏膛豚滩蜕大驼佃提体套拖台图厅吐颓舔倘碳挺剔塘屠汰廷腾逃愉徒题天桃捅苔迢潭泰她褪掏唐投 涛庭田铁痛童毯添誊讨塌糖团痰推凸同途妥太听梯拓塔托坦叹涂透瘫剃铜条蜓它亭帖通甜头惕兔藤揣驮陶啼秃躺谭疼淌他坛叨特腿" },
    { "ta", "它蹋塌拓塔他踏她" },
    { "tai", "态大汰太抬胎苔泰台" },
    { "tan", "檀谈探瘫谭炭碳弹贪摊坛坦滩潭毯痰叹" },
    { "tang", "堂唐倘膛糖躺趟淌塘棠汤烫" },
    { "tao", "逃萄掏涛讨桃滔套淘叨跳陶" },
    { "te", "特" },
    { "teng", "誊疼藤腾" },
    { "ti", "涕梯蹄剔替题剃啼踢惕弟屉提体" },
    { "tian", "舔甜天田甸佃填恬添" },
    { "tiao", "调挑条迢跳" },
    { "tie", "铁贴帖" },
    { "ting", "厅庭亭听挺廷艇停蜓" },
    { "tong", "统同捅筒通瞳桐痛铜童彤桶" },
    { "tou", "愉投头透偷" },
    { "tu", "突涂吐徒途土秃兔屠凸图" },
    { "tuan", "揣团" },
    { "tui", "退颓蜕弟推褪腿" },
    { "tun", "褪臀豚囤屯吞" },
    { "tuo", "妥唾拓托驼椭脱拖驮鸵" },
    { "u", "" },
    { "v", "" },
    { "wa", "娃挖袜洼哇瓦蛙凹" },
    { "wai", "歪外" },
    { "wan", "碗玩丸惋豌万挽腕宛晚湾完蔓皖弯婉顽" },
    { "wang", "往妄枉王忘望亡网汪旺" },
    { "wei", "伪胃苇巍违惟喂魏蔚谓纬微帷位危味围未薇萎猬尾偎为慰威尉伟唯维畏委卫" },
    { "wen", "文紊蚊瘟温稳纹吻闻问" },
    { "weng", "嗡翁" },
    { "wo", "沃我蜗窝涡握卧" },
    { "wu", "悟梧呜吴捂乌武伍五芜侮鹉舞务屋勿蜈戊亡吾午巫误恶污无物诬雾" },
    { "x", "吸线厢循械咸契凶须吁胁虚啸消肖歇翔绪嚣勋学臭瞎笑悬蓄癣叶相寻掀芯洒镶系锡宪淆汛婿渲宿姓牺馨潇降协屑殉些弦券像旭夕息鞋锌熏辛响卸徐匣旬序训见血迅吓星纤嫌栖效袖雪膝型湘绣幸小醒厦泄惜修袭仙刑险暇 希巡形想悉薛讯县峡向挟新懈项羡享腊限晰猩嘻祥宣巷夏洗斜邪衅戌炫羊雄孝霄狭溪杏哮箱嗅蝎喜蟹犀羞详轩隙携酗硝谐熙穴泻戏掺胸销旋玄墟献媳衔叙恤腺省休鲜腥需唬兄蟋熄辖细西昔絮写询锈宵俏靴校秀绚汹稀徙霞行性薪 晓喧贤箫显心虾现橡香朽驯先削解续选席陷象馅信习下熊萧孙闲匈逊谢畜兴析侠欣许乡" },
    { "xi", "稀席希洒昔膝媳吸腊习晰熙犀戏徙夕锡嘻惜息悉栖蟋隙系牺熄析洗喜溪细袭西" },
    { "xia", "下辖夏瞎霞侠匣暇厦唬峡狭吓虾" },
    { "xian", "宪馅羡弦献线见限衔腺纤咸掺嫌闲陷贤县显先仙掀洗鲜现险" },
    { "xiang", "香享箱象像湘想镶羊厢祥相翔乡响详巷向降橡项" },
    { "xiao", "嚣宵小笑萧淆晓孝销霄箫效削俏啸消肖校潇硝哮" },
    { "xie", "谐写些血蝎蟹泻械泄契叶鞋谢携解卸胁斜挟邪歇懈协屑" },
    { "xin", "薪锌辛欣馨芯新心衅信" },
    { "xing", "省型刑醒星性猩杏姓行形腥兴幸" },
    { "xiong", "匈熊雄兄凶汹胸" },
    { "xiu", "秀锈休袖羞朽宿嗅绣臭修" },
    { "xu", "戌序墟叙恤旭絮休蓄须需虚畜徐续吁邪许酗绪婿" },
    { "xuan", "炫券悬癣轩宣喧选渲县旋玄绚" },
    { "xue", "薛穴血削学雪靴" },
    { "xun", "殉训逊巡循孙汛寻询驯熏讯旬迅勋" },
    { "ya", "呀崖丫讶押压牙鸦涯雅哑芽亚邪鸭衙轧" },
    { "yan", "言研掩堰烟蜒淹唁焉檐眼铅颜砚验盐艳阎演岩焰殷咽雁燕炎厌严宴衍沿谚延" },
    { "yang", "央漾扬羊氧鸯阳样痒详仰殃秧杨洋养" },
    { "yao", "要耀舀侥么乐邀妖谣夭咬肴摇姚吆窑疟钥腰约遥尧药" },
    { "ye", "邪射喝液爷冶腋野也业夜椰咽拽叶页" },
    { "yi", "伊疙亿胰邑尾以移怡宜益仪射译易泄遗役谊抑矣夷绎屹蛾异疑依逸毅蛇衣疫壹艺溢贻姨翼一医食椅议义忆已蚁乙倚艾意亦" },
    { "yin", "蚓阴寅饮隐引吟茵因殷瘾淫印音姻荫银" },
    { "ying", "荧映莹赢莺鹦硬鹰婴应盈迎萤影英颖景营樱蝇" },
    { "yo", "哟" },
    { "yong", "踊涌咏勇用庸永拥佣泳" },
    { "you", "邮尤游诱有悠由酉犹佑优油友忧右又幼幽" },
    { "yu", "玉芋愚御娱舆欲禹羽愉语预榆予迂遇余雨豫鱼屿隅宇誉愈与粥喻吾郁寓裕奥域狱浴逾吁尉于渝邪育淤渔" },
    { "yuan", "袁圆怨员愿源宛鸳渊缘原苑院园冤猿元远援" },
    { "yue", "阅越粤悦岳月跃兑乐钥约曰说" },
    { "yun", "耘员陨韵允孕酝运匀云蕴晕" },
    { "z", "造嘴赠揍卒祖阻早蚤咨总仔暂宗踪足纵噪灶撮赃责字躁再昨赞糟罪枣在族子钻资宰栽佐尊遭曾醉咋座砸杂自憎组左凿兹载综怎侧咱作走藻灾皂增紫吱滋澡燥葬姊从藏最琢贼扎坐棕做租择泽姿脏则哉奏遵籽" },
    { "za", "咋咱砸杂扎" },
    { "zai", "再在宰载栽哉仔灾" },
    { "zan", "暂咱赞" },
    { "zang", "脏赃藏葬" },
    { "zao", "躁皂澡造蚤枣燥糟早噪遭灶藻凿" },
    { "ze", "咋则责侧择泽" },
    { "zei", "贼" },
    { "zen", "怎" },
    { "zeng", "憎增赠曾综" },
    { "zh", "枕贞斩疹兆珍盏摘烛止逐周睁庄妆转粘遮职枝至长蒸胀准浙筝州执注直铸著砖帚芝震质喳掷赘属淳智拽侄指掌窒真撞责涨驻术阵住旨召宁缀丈辙钟瞩值浊种桌查招赚毡识置植氏专殖纸张终筑针祝章罩祭屯狰赵闸重争调蜘斟窄皱这粥眨诸制肇啄占整知支状政酌滞珠照征宅栈咋椎站茁挚帜账猪治昼织仗炸秩拯煮趾追肘朝障樟轧撰诊拄轴只展郑谆锥者稚侧爪嘲志幢肿绽填众榨中振吱汁缴贮乍肢证桩壮仲骤帐抓怔宙战洲斋拓杖蛛昭着柱辗蚣折侦崭 朱诈主沼捉之舟灼传琢助株瞻债址装症脂扎拙坠揣择彰竹找丁栅咒蔗挣嘱镇渣卓蛀颤忠正寨衷哲致沾" },
    { "zha", "栅咋渣榨喳炸诈乍扎闸查轧眨" },
    { "zhai", "宅窄斋责侧债摘择寨祭" },
    { "zhan", "盏栈战毡颤斩崭粘瞻展站占沾绽辗" },
    { "zhang", "丈掌帐障樟张账涨胀仗杖章彰长" },
    { "zhao", "肇朝爪昭嘲赵沼着兆招照罩召找" },
    { "zhe", "者辙蔗折这着著浙遮哲" },
    { "zhei", "这" },
    { "zhen", "枕疹珍针侦贞诊填斟震真振阵镇" },
    { "zheng", "丁征争怔挣筝睁政症正郑蒸证拯狰整" },
    { "zhi", "蜘挚帜治值织拓知止秩脂植氏吱殖置枝纸趾识之执直稚芝制址掷志至智侄指窒支致汁职肢质滞旨只" },
    { "zhong", "重众钟中终肿种蚣忠仲衷" },
    { "zhou", "调咒宙肘帚粥骤皱洲舟昼州周轴" },
    { "zhu", "宁逐蛛瞩猪铸烛煮柱蛀朱主拄著祝筑注驻助株珠属竹术嘱贮住诸" },
    { "zhua", "爪抓" },
    { "zhuai", "拽转" },
    { "zhuan", "专砖传赚撰转" },
    { "zhuang", "庄妆撞状装幢桩壮" },
    { "zhui", "缀椎锥赘坠揣追" },
    { "zhun", "谆准淳屯" },
    { "zhuo", "茁著琢缴着啄捉浊桌酌卓拙灼" },
    { "zi", "滋咨姊自兹仔资子姿吱字籽紫" },
    { "zong", "宗踪纵总从综棕" },
    { "zou", "揍奏走" },
    { "zu", "足阻组族卒祖租" },
    { "zuan", "钻" },
    { "zui", "最醉嘴罪" },
    { "zun", "尊遵" },
    { "zuo", "琢座昨撮佐坐作左做" },
    {NULL, NULL}
};
#endif


/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
static void lv_memzero(void *p, size_t size)
{
    if(p)
    {
        memset(p, 0, size);
    }
}
lv_obj_t * lv_ime_pinyin_create(lv_obj_t * parent)
{
    LV_LOG_INFO("begin");
    lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
    lv_obj_class_init_obj(obj);
    return obj;
}


/*=====================
 * Setter functions
 *====================*/

/**
 * Set the keyboard of Pinyin input method.
 * @param obj  pointer to a Pinyin input method object
 * @param dict pointer to a Pinyin input method keyboard
 */
void lv_ime_pinyin_set_keyboard(lv_obj_t * obj, lv_obj_t * kb)
{
    if(kb) {
        LV_ASSERT_OBJ(kb, &lv_keyboard_class);
    }

    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    pinyin_ime->kb = kb;
    lv_obj_add_event_cb(pinyin_ime->kb, lv_ime_pinyin_kb_event, LV_EVENT_VALUE_CHANGED, obj);
    lv_obj_align_to(pinyin_ime->cand_panel, pinyin_ime->kb, LV_ALIGN_OUT_TOP_MID, 0, 0);
}

/**
 * Set the dictionary of Pinyin input method.
 * @param obj  pointer to a Pinyin input method object
 * @param dict pointer to a Pinyin input method dictionary
 */
void lv_ime_pinyin_set_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);

    init_pinyin_dict(obj, dict);
}

/**
 * Set mode, 26-key input(k26) or 9-key input(k9).
 * @param obj  pointer to a Pinyin input method object
 * @param mode   the mode from 'lv_keyboard_mode_t'
 */
void lv_ime_pinyin_set_mode(lv_obj_t * obj, lv_ime_pinyin_mode_t mode)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    LV_ASSERT_OBJ(pinyin_ime->kb, &lv_keyboard_class);

    pinyin_ime->mode = mode;

#if LV_IME_PINYIN_USE_K9_MODE
    if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
        pinyin_k9_init_data(obj);
        lv_keyboard_set_map(pinyin_ime->kb, LV_KEYBOARD_MODE_USER_1, (const char **)lv_btnm_def_pinyin_k9_map,
                            default_kb_ctrl_k9_map);
        lv_keyboard_set_mode(pinyin_ime->kb, LV_KEYBOARD_MODE_USER_1);
    }
#endif
}

/*=====================
 * Getter functions
 *====================*/

/**
 * Set the dictionary of Pinyin input method.
 * @param obj  pointer to a Pinyin IME object
 * @return     pointer to the Pinyin IME keyboard
 */
lv_obj_t * lv_ime_pinyin_get_kb(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    return pinyin_ime->kb;
}

/**
 * Set the dictionary of Pinyin input method.
 * @param obj  pointer to a Pinyin input method object
 * @return     pointer to the Pinyin input method candidate panel
 */
lv_obj_t * lv_ime_pinyin_get_cand_panel(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    return pinyin_ime->cand_panel;
}

/**
 * Set the dictionary of Pinyin input method.
 * @param obj  pointer to a Pinyin input method object
 * @return     pointer to the Pinyin input method dictionary
 */
lv_pinyin_dict_t * lv_ime_pinyin_get_dict(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    return pinyin_ime->dict;
}

/*=====================
 * Other functions
 *====================*/

/**********************
 *   STATIC FUNCTIONS
 **********************/

static void lv_ime_pinyin_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
    LV_UNUSED(class_p);
    LV_TRACE_OBJ_CREATE("begin");

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    uint16_t py_str_i = 0;
    uint16_t btnm_i = 0;
    for(btnm_i = 0; btnm_i < (LV_IME_PINYIN_CAND_TEXT_NUM + 3); btnm_i++) {
        if(btnm_i == 0) {
            lv_btnm_def_pinyin_sel_map[btnm_i] = "<";
        }
        else if(btnm_i == (LV_IME_PINYIN_CAND_TEXT_NUM + 1)) {
            lv_btnm_def_pinyin_sel_map[btnm_i] = ">";
        }
        else if(btnm_i == (LV_IME_PINYIN_CAND_TEXT_NUM + 2)) {
            lv_btnm_def_pinyin_sel_map[btnm_i] = "";
        }
        else {
            lv_pinyin_cand_str[py_str_i][0] = ' ';
            lv_btnm_def_pinyin_sel_map[btnm_i] = lv_pinyin_cand_str[py_str_i];
            py_str_i++;
        }
    }

    pinyin_ime->mode = LV_IME_PINYIN_MODE_K26;
    pinyin_ime->py_page = 0;
    pinyin_ime->ta_count = 0;
    pinyin_ime->cand_num = 0;
    lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));
    lv_memzero(pinyin_ime->py_num, sizeof(pinyin_ime->py_num));
    lv_memzero(pinyin_ime->py_pos, sizeof(pinyin_ime->py_pos));

    lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);

#if LV_IME_PINYIN_USE_DEFAULT_DICT
    init_pinyin_dict(obj, lv_ime_pinyin_def_dict);
#endif

    /* Init pinyin_ime->cand_panel */
    pinyin_ime->cand_panel = lv_btnmatrix_create(lv_obj_get_screen(obj));
    lv_btnmatrix_set_map(pinyin_ime->cand_panel, (const char **)lv_btnm_def_pinyin_sel_map);
    lv_obj_set_size(pinyin_ime->cand_panel, LV_PCT(100), LV_PCT(5));
    lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);

    lv_btnmatrix_set_one_checked(pinyin_ime->cand_panel, true);

    /* Set cand_panel style*/
    // Default style
    lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_70, 0);
    lv_obj_set_style_border_width(pinyin_ime->cand_panel, 0, 0);
    lv_obj_set_style_pad_all(pinyin_ime->cand_panel, 8, 0);
    lv_obj_set_style_pad_gap(pinyin_ime->cand_panel, 0, 0);
    lv_obj_set_style_radius(pinyin_ime->cand_panel, 0, 0);
    lv_obj_set_style_pad_gap(pinyin_ime->cand_panel, 0, 0);
    lv_obj_set_style_base_dir(pinyin_ime->cand_panel, LV_BASE_DIR_LTR, 0);

    // LV_PART_ITEMS style
    lv_obj_set_style_radius(pinyin_ime->cand_panel, 12, LV_PART_ITEMS);
    lv_obj_set_style_bg_color(pinyin_ime->cand_panel, lv_color_white(), LV_PART_ITEMS);
    lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_0, LV_PART_ITEMS);
    lv_obj_set_style_shadow_opa(pinyin_ime->cand_panel, LV_OPA_0, LV_PART_ITEMS);

    // LV_PART_ITEMS | LV_STATE_PRESSED style
    lv_obj_set_style_bg_opa(pinyin_ime->cand_panel, LV_OPA_COVER, LV_PART_ITEMS | LV_STATE_PRESSED);
    lv_obj_set_style_bg_color(pinyin_ime->cand_panel, lv_color_white(), LV_PART_ITEMS | LV_STATE_PRESSED);

    /* event handler */
    lv_obj_add_event_cb(pinyin_ime->cand_panel, lv_ime_pinyin_cand_panel_event, LV_EVENT_VALUE_CHANGED, obj);
    lv_obj_add_event_cb(obj, lv_ime_pinyin_style_change_event, LV_EVENT_STYLE_CHANGED, NULL);

#if LV_IME_PINYIN_USE_K9_MODE
    pinyin_ime->k9_input_str_len = 0;
    pinyin_ime->k9_py_ll_pos = 0;
    pinyin_ime->k9_legal_py_count = 0;
    lv_memzero(pinyin_ime->k9_input_str, LV_IME_PINYIN_K9_MAX_INPUT);

    pinyin_k9_init_data(obj);

    _lv_ll_init(&(pinyin_ime->k9_legal_py_ll), sizeof(ime_pinyin_k9_py_str_t));
#endif
}


static void lv_ime_pinyin_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
    LV_UNUSED(class_p);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    if(lv_obj_is_valid(pinyin_ime->kb))
        lv_obj_del(pinyin_ime->kb);

    if(lv_obj_is_valid(pinyin_ime->cand_panel))
        lv_obj_del(pinyin_ime->cand_panel);
}


static void lv_ime_pinyin_kb_event(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * kb = lv_event_get_target(e);
    lv_obj_t * obj = lv_event_get_user_data(e);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

#if LV_IME_PINYIN_USE_K9_MODE
    static const char * k9_py_map[8] = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
#endif

    if(code == LV_EVENT_VALUE_CHANGED) {
        uint16_t btn_id  = lv_btnmatrix_get_selected_btn(kb);
        if(btn_id == LV_BTNMATRIX_BTN_NONE) return;

        const char * txt = lv_btnmatrix_get_btn_text(kb, lv_btnmatrix_get_selected_btn(kb));
        if(txt == NULL) return;

        lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);

#if LV_IME_PINYIN_USE_K9_MODE
        if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {

            uint16_t tmp_btn_str_len = strlen(pinyin_ime->input_char);
            if((btn_id >= 16) && (tmp_btn_str_len > 0) && (btn_id < (16 + LV_IME_PINYIN_K9_CAND_TEXT_NUM))) {
                lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));
                strcat(pinyin_ime->input_char, txt);
                pinyin_input_proc(obj);

                for(int index = 0; index < (pinyin_ime->ta_count + tmp_btn_str_len); index++) {
                    lv_textarea_del_char(ta);
                }

                pinyin_ime->ta_count = tmp_btn_str_len;
                pinyin_ime->k9_input_str_len = tmp_btn_str_len;
                lv_textarea_add_text(ta, pinyin_ime->input_char);

                return;
            }
        }
#endif

        if(strcmp(txt, "Enter") == 0 || strcmp(txt, LV_SYMBOL_NEW_LINE) == 0) {
            pinyin_ime_clear_data(obj);
            lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
        }
        else if(strcmp(txt, LV_SYMBOL_BACKSPACE) == 0) {
            // del input char
            if(pinyin_ime->ta_count > 0) {
                if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26)
                    pinyin_ime->input_char[pinyin_ime->ta_count - 1] = '\0';
#if LV_IME_PINYIN_USE_K9_MODE
                else
                    pinyin_ime->k9_input_str[pinyin_ime->ta_count - 1] = '\0';
#endif

                pinyin_ime->ta_count--;
                if(pinyin_ime->ta_count <= 0) {
                    pinyin_ime_clear_data(obj);
                    lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
                }
                else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) {
                    pinyin_input_proc(obj);
                }
#if LV_IME_PINYIN_USE_K9_MODE
                else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
                    pinyin_ime->k9_input_str_len = strlen(pinyin_ime->input_char) - 1;
                    pinyin_k9_get_legal_py(obj, pinyin_ime->k9_input_str, k9_py_map);
                    pinyin_k9_fill_cand(obj);
                    pinyin_input_proc(obj);
                    pinyin_ime->ta_count--;
                }
#endif
            }
        }
        else if((strcmp(txt, "ABC") == 0) || (strcmp(txt, "abc") == 0) || (strcmp(txt, "1#") == 0) ||
                (strcmp(txt, LV_SYMBOL_OK) == 0)) {
            pinyin_ime_clear_data(obj);
            return;
        }
        else if(strcmp(txt, "123") == 0) {
            for(uint16_t i = 0; i < strlen(txt); i++)
                lv_textarea_del_char(ta);

            pinyin_ime_clear_data(obj);
            lv_textarea_set_cursor_pos(ta, LV_TEXTAREA_CURSOR_LAST);
            lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9_NUMBER);
            lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);
            lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
        }
        else if(strcmp(txt, LV_SYMBOL_KEYBOARD) == 0) {
            if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) {
                lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9);
            }
            else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
                lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K26);
                lv_keyboard_set_mode(pinyin_ime->kb, LV_KEYBOARD_MODE_TEXT_LOWER);
            }
            else if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9_NUMBER) {
                lv_ime_pinyin_set_mode(obj, LV_IME_PINYIN_MODE_K9);
            }
            pinyin_ime_clear_data(obj);
        }
        else if((pinyin_ime->mode == LV_IME_PINYIN_MODE_K26) && ((txt[0] >= 'a' && txt[0] <= 'z') || (txt[0] >= 'A' &&
                                                                                                      txt[0] <= 'Z'))) {
            strcat(pinyin_ime->input_char, txt);
            pinyin_input_proc(obj);
            pinyin_ime->ta_count++;
        }
#if LV_IME_PINYIN_USE_K9_MODE
        else if((pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) && (txt[0] >= 'a' && txt[0] <= 'z')) {
            for(uint16_t i = 0; i < 8; i++) {
                if((strcmp(txt, k9_py_map[i]) == 0) || (strcmp(txt, "abc ") == 0)) {
                    if(strcmp(txt, "abc ") == 0)    pinyin_ime->k9_input_str_len += strlen(k9_py_map[i]) + 1;
                    else                            pinyin_ime->k9_input_str_len += strlen(k9_py_map[i]);
                    pinyin_ime->k9_input_str[pinyin_ime->ta_count] = 50 + i;

                    break;
                }
            }
            pinyin_k9_get_legal_py(obj, pinyin_ime->k9_input_str, k9_py_map);
            pinyin_k9_fill_cand(obj);
            pinyin_input_proc(obj);
        }
        else if(strcmp(txt, LV_SYMBOL_LEFT) == 0) {
            pinyin_k9_cand_page_proc(obj, 0);
        }
        else if(strcmp(txt, LV_SYMBOL_RIGHT) == 0) {
            pinyin_k9_cand_page_proc(obj, 1);
        }
#endif
    }
}


static void lv_ime_pinyin_cand_panel_event(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * cand_panel = lv_event_get_target(e);
    lv_obj_t * obj = (lv_obj_t *)lv_event_get_user_data(e);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    if(code == LV_EVENT_VALUE_CHANGED) {
        uint32_t id = lv_btnmatrix_get_selected_btn(cand_panel);
        if(id == 0) {
            pinyin_page_proc(obj, 0);
            return;
        }
        if(id == (LV_IME_PINYIN_CAND_TEXT_NUM + 1)) {
            pinyin_page_proc(obj, 1);
            return;
        }

        const char * txt = lv_btnmatrix_get_btn_text(cand_panel, id);
        lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
        uint16_t index = 0;
        for(index = 0; index < pinyin_ime->ta_count; index++)
            lv_textarea_del_char(ta);

        lv_textarea_add_text(ta, txt);

        pinyin_ime_clear_data(obj);
    }
}


static void pinyin_input_proc(lv_obj_t * obj)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    pinyin_ime->cand_str = pinyin_search_matching(obj, pinyin_ime->input_char, &pinyin_ime->cand_num);
    if(pinyin_ime->cand_str == NULL) {
        return;
    }

    pinyin_ime->py_page = 0;

    for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
        memset(lv_pinyin_cand_str[i], 0x00, sizeof(lv_pinyin_cand_str[i]));
        lv_pinyin_cand_str[i][0] = ' ';
    }

    // fill buf
    for(uint8_t i = 0; (i < pinyin_ime->cand_num && i < LV_IME_PINYIN_CAND_TEXT_NUM); i++) {
        for(uint8_t j = 0; j < 3; j++) {
            lv_pinyin_cand_str[i][j] = pinyin_ime->cand_str[i * 3 + j];
        }
    }

    lv_obj_clear_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
}

static void pinyin_page_proc(lv_obj_t * obj, uint16_t dir)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;
    uint16_t page_num = pinyin_ime->cand_num / LV_IME_PINYIN_CAND_TEXT_NUM;
    uint16_t sur = pinyin_ime->cand_num % LV_IME_PINYIN_CAND_TEXT_NUM;

    if(dir == 0) {
        if(pinyin_ime->py_page) {
            pinyin_ime->py_page--;
        }
    }
    else {
        if(sur == 0) {
            page_num -= 1;
        }
        if(pinyin_ime->py_page < page_num) {
            pinyin_ime->py_page++;
        }
        else return;
    }

    for(uint8_t i = 0; i < LV_IME_PINYIN_CAND_TEXT_NUM; i++) {
        memset(lv_pinyin_cand_str[i], 0x00, sizeof(lv_pinyin_cand_str[i]));
        lv_pinyin_cand_str[i][0] = ' ';
    }

    // fill buf
    uint16_t offset = pinyin_ime->py_page * (3 * LV_IME_PINYIN_CAND_TEXT_NUM);
    for(uint8_t i = 0; (i < pinyin_ime->cand_num && i < LV_IME_PINYIN_CAND_TEXT_NUM); i++) {
        if((sur > 0) && (pinyin_ime->py_page == page_num)) {
            if(i > sur)
                break;
        }
        for(uint8_t j = 0; j < 3; j++) {
            lv_pinyin_cand_str[i][j] = pinyin_ime->cand_str[offset + (i * 3) + j];
        }
    }
}


static void lv_ime_pinyin_style_change_event(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * obj = lv_event_get_target(e);

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    if(code == LV_EVENT_STYLE_CHANGED) {
        const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
        lv_obj_set_style_text_font(pinyin_ime->cand_panel, font, 0);
    }
}


static void init_pinyin_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    char headletter = 'a';
    uint16_t offset_sum = 0;
    uint16_t offset_count = 0;
    uint16_t letter_calc = 0;

    pinyin_ime->dict = dict;

    for(uint16_t i = 0; ; i++) {
        if((NULL == (dict[i].py)) || (NULL == (dict[i].py_mb))) {
            headletter = dict[i - 1].py[0];
            letter_calc = headletter - 'a';
            pinyin_ime->py_num[letter_calc] = offset_count;
            break;
        }

        if(headletter == (dict[i].py[0])) {
            offset_count++;
        }
        else {
            headletter = dict[i].py[0];
            letter_calc = headletter - 'a';
            pinyin_ime->py_num[letter_calc - 1] = offset_count;
            offset_sum += offset_count;
            pinyin_ime->py_pos[letter_calc] = offset_sum;

            offset_count = 1;
        }
    }
}


static char * pinyin_search_matching(lv_obj_t * obj, char * py_str, uint16_t * cand_num)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    lv_pinyin_dict_t * cpHZ;
    uint8_t index, len = 0, offset;
    volatile uint8_t count = 0;

    if(*py_str == '\0')    return NULL;
    if(*py_str == 'i')     return NULL;
    if(*py_str == 'u')     return NULL;
    if(*py_str == 'v')     return NULL;

    offset = py_str[0] - 'a';
    len = strlen(py_str);

    cpHZ  = &pinyin_ime->dict[pinyin_ime->py_pos[offset]];
    count = pinyin_ime->py_num[offset];

    while(count--) {
        for(index = 0; index < len; index++) {
            if(*(py_str + index) != *((cpHZ->py) + index)) {
                break;
            }
        }

        // perfect match
        if(len == 1 || index == len) {
            // The Chinese character in UTF-8 encoding format is 3 bytes
            * cand_num = strlen((const char *)(cpHZ->py_mb)) / 3;
            return (char *)(cpHZ->py_mb);
        }
        cpHZ++;
    }
    return NULL;
}

static void pinyin_ime_clear_data(lv_obj_t * obj)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

#if LV_IME_PINYIN_USE_K9_MODE
    if(pinyin_ime->mode == LV_IME_PINYIN_MODE_K9) {
        pinyin_ime->k9_input_str_len = 0;
        pinyin_ime->k9_py_ll_pos = 0;
        pinyin_ime->k9_legal_py_count = 0;
        lv_memzero(pinyin_ime->k9_input_str,  LV_IME_PINYIN_K9_MAX_INPUT);
        lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");
    }
#endif

    pinyin_ime->ta_count = 0;
    lv_memzero(lv_pinyin_cand_str, (sizeof(lv_pinyin_cand_str)));
    lv_memzero(pinyin_ime->input_char, sizeof(pinyin_ime->input_char));

    lv_obj_add_flag(pinyin_ime->cand_panel, LV_OBJ_FLAG_HIDDEN);
}


#if LV_IME_PINYIN_USE_K9_MODE
static void pinyin_k9_init_data(lv_obj_t * obj)
{
    LV_UNUSED(obj);

    uint16_t py_str_i = 0;
    uint16_t btnm_i = 0;
    for(btnm_i = 19; btnm_i < (LV_IME_PINYIN_K9_CAND_TEXT_NUM + 21); btnm_i++) {
        if(py_str_i == LV_IME_PINYIN_K9_CAND_TEXT_NUM) {
            strcpy(lv_pinyin_k9_cand_str[py_str_i], LV_SYMBOL_RIGHT"\0");
        }
        else if(py_str_i == LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1) {
            strcpy(lv_pinyin_k9_cand_str[py_str_i], "\0");
        }
        else {
            strcpy(lv_pinyin_k9_cand_str[py_str_i], " \0");
        }

        lv_btnm_def_pinyin_k9_map[btnm_i] = lv_pinyin_k9_cand_str[py_str_i];
        py_str_i++;
    }

    default_kb_ctrl_k9_map[0]  = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[4]  = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[5]  = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[9]  = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[10] = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[14] = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[15] = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
    default_kb_ctrl_k9_map[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 16] = LV_KEYBOARD_CTRL_BTN_FLAGS | 1;
}

static void pinyin_k9_get_legal_py(lv_obj_t * obj, char * k9_input, const char * py9_map[])
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    uint16_t len = strlen(k9_input);

    if((len == 0) || (len >= LV_IME_PINYIN_K9_MAX_INPUT)) {
        return;
    }

    char py_comp[LV_IME_PINYIN_K9_MAX_INPUT] = {0};
    int mark[LV_IME_PINYIN_K9_MAX_INPUT] = {0};
    int index = 0;
    int flag = 0;
    uint16_t count = 0;

    uint32_t ll_len = 0;
    ime_pinyin_k9_py_str_t * ll_index = NULL;

    ll_len = _lv_ll_get_len(&pinyin_ime->k9_legal_py_ll);
    ll_index = _lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);

    while(index != -1) {
        if(index == len) {
            if(pinyin_k9_is_valid_py(obj, py_comp)) {
                if((count >= ll_len) || (ll_len == 0)) {
                    ll_index = _lv_ll_ins_tail(&pinyin_ime->k9_legal_py_ll);
                    strcpy(ll_index->py_str, py_comp);
                }
                else if((count < ll_len)) {
                    strcpy(ll_index->py_str, py_comp);
                    ll_index = _lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index);
                }
                count++;
            }
            index--;
        }
        else {
            flag = mark[index];
            if((size_t)flag < strlen(py9_map[k9_input[index] - '2'])) {
                py_comp[index] = py9_map[k9_input[index] - '2'][flag];
                mark[index] = mark[index] + 1;
                index++;
            }
            else {
                mark[index] = 0;
                index--;
            }
        }
    }

    if(count > 0) {
        pinyin_ime->ta_count++;
        pinyin_ime->k9_legal_py_count = count;
    }
}


/*true: visible; false: not visible*/
static bool pinyin_k9_is_valid_py(lv_obj_t * obj, char * py_str)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    lv_pinyin_dict_t * cpHZ = NULL;
    uint8_t index = 0, len = 0, offset = 0;
    volatile uint8_t count = 0;

    if(*py_str == '\0')    return false;
    if(*py_str == 'i')     return false;
    if(*py_str == 'u')     return false;
    if(*py_str == 'v')     return false;

    offset = py_str[0] - 'a';
    len = strlen(py_str);

    cpHZ  = &pinyin_ime->dict[pinyin_ime->py_pos[offset]];
    count = pinyin_ime->py_num[offset];

    while(count--) {
        for(index = 0; index < len; index++) {
            if(*(py_str + index) != *((cpHZ->py) + index)) {
                break;
            }
        }

        // perfect match
        if(len == 1 || index == len) {
            return true;
        }
        cpHZ++;
    }
    return false;
}


static void pinyin_k9_fill_cand(lv_obj_t * obj)
{
    static uint16_t len = 0;
    uint16_t index = 0, tmp_len = 0;
    ime_pinyin_k9_py_str_t * ll_index = NULL;

    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    tmp_len = pinyin_ime->k9_legal_py_count;

    if(tmp_len != len) {
        lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");
        len = tmp_len;
    }

    ll_index = _lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);
    strcpy(pinyin_ime->input_char, ll_index->py_str);
    while(ll_index) {
        if((index >= LV_IME_PINYIN_K9_CAND_TEXT_NUM) || \
           (index >= pinyin_ime->k9_legal_py_count))
            break;

        strcpy(lv_pinyin_k9_cand_str[index], ll_index->py_str);
        ll_index = _lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
        index++;
    }
    pinyin_ime->k9_py_ll_pos = index;

    lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
    for(index = 0; index < pinyin_ime->k9_input_str_len; index++) {
        lv_textarea_del_char(ta);
    }
    pinyin_ime->k9_input_str_len = strlen(pinyin_ime->input_char);
    lv_textarea_add_text(ta, pinyin_ime->input_char);
}


static void pinyin_k9_cand_page_proc(lv_obj_t * obj, uint16_t dir)
{
    lv_ime_pinyin_t * pinyin_ime = (lv_ime_pinyin_t *)obj;

    lv_obj_t * ta = lv_keyboard_get_textarea(pinyin_ime->kb);
    uint16_t ll_len =  _lv_ll_get_len(&pinyin_ime->k9_legal_py_ll);

    if((ll_len > LV_IME_PINYIN_K9_CAND_TEXT_NUM) && (pinyin_ime->k9_legal_py_count > LV_IME_PINYIN_K9_CAND_TEXT_NUM)) {
        ime_pinyin_k9_py_str_t * ll_index = NULL;
        int count = 0;

        ll_index = _lv_ll_get_head(&pinyin_ime->k9_legal_py_ll);
        while(ll_index) {
            if(count >= pinyin_ime->k9_py_ll_pos)   break;

            ll_index = _lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
            count++;
        }

        if((NULL == ll_index) && (dir == 1))   return;

        lv_memzero(lv_pinyin_k9_cand_str, sizeof(lv_pinyin_k9_cand_str));
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM], LV_SYMBOL_RIGHT"\0");
        strcpy(lv_pinyin_k9_cand_str[LV_IME_PINYIN_K9_CAND_TEXT_NUM + 1], "\0");

        // next page
        if(dir == 1) {
            count = 0;
            while(ll_index) {
                if(count >= (LV_IME_PINYIN_K9_CAND_TEXT_NUM - 1))
                    break;

                strcpy(lv_pinyin_k9_cand_str[count], ll_index->py_str);
                ll_index = _lv_ll_get_next(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the next list*/
                count++;
            }
            pinyin_ime->k9_py_ll_pos += count - 1;

        }
        // previous page
        else {
            count = LV_IME_PINYIN_K9_CAND_TEXT_NUM - 1;
            ll_index = _lv_ll_get_prev(&pinyin_ime->k9_legal_py_ll, ll_index);
            while(ll_index) {
                if(count < 0)  break;

                strcpy(lv_pinyin_k9_cand_str[count], ll_index->py_str);
                ll_index = _lv_ll_get_prev(&pinyin_ime->k9_legal_py_ll, ll_index); /*Find the previous list*/
                count--;
            }

            if(pinyin_ime->k9_py_ll_pos > LV_IME_PINYIN_K9_CAND_TEXT_NUM)
                pinyin_ime->k9_py_ll_pos -= 1;
        }

        lv_textarea_set_cursor_pos(ta, LV_TEXTAREA_CURSOR_LAST);
    }
}

#endif  /*LV_IME_PINYIN_USE_K9_MODE*/

#endif  /*LV_USE_IME_PINYIN*/
